package general;

import java.util.ArrayList;

public class Perlin
{
	int nbDegree = 2;

	public static float[][] conversion(float[][] g , int noise )
	{
		float d[][] = new float[g.length][g[0].length];

		int periode = 1;
		float amplitude = 1;

		for( int b = 0 ; b < noise ; b++ )
		{
			System.out.println("	Filtre " + b + " debut");
			
			for( int i = 0 ; i < d.length ; i++ )
			{
				for( int j = 0 ; j < d[0].length ; j++ )
				{
					d[i][j] = 0;
				}
			}
			
			for( int i = 0 ; i < d.length ; i += periode )
			{
				for( int j = 0 ; j < d[0].length ; j += periode )
				{
					d[i][j] = (float) (Math.random() * amplitude);
				}
			}
			//presenter( d );
			
			for( int i = 0 ; i < d.length-periode ; i += periode )
			{
				for( int j = 0 ; j < d[0].length-periode ; j += periode )
				{
					for( int k = 0 ; k < periode+1 ; k++ )
					{
						for( int l = 0 ; l < periode+1 ; l++)
						{
							float x = (float)k/(float)periode;
							float y = (float)l/(float)periode;
							
							
							d[i+k][j+l] = interpolation_cos2D( d[i][j] , d[i+periode][j] , d[i][j+periode] , d[i+periode][j+periode] , x, y);
						}
					}
				}
			}
			
			for( int i = 0 ; i < d.length ; i++ )
			{
				for( int j = 0 ; j < d[0].length ; j++ )
				{
					g[i][j] += d[i][j];
				}
			}
			
			amplitude *= 2;
			periode *= 2;
			
			System.out.println("	Filtre " + b + " fini");
		}

		//presenter( d );

		return g;
	}

	public static void presenter( float g[][] )
	{
		//System.out.println(g.length );
		for( int i = 0 ; i < g.length ; i++ )
		{
			for( int j = 0 ; j < g[0].length ; j++ )
			{
				System.out.print( affichagefloat( g[i][j] ) + " ");
			}
			System.out.println();
		}
		
		System.out.println();
	}
	
	public static String affichagefloat(float d)
	{
		return (d + "000000000").substring(0, 4);
	}

	static float interpolation_cos(float a, float b, float x)
	{
		float k = (float) ((1 - Math.cos(x * Math.PI)) / 2);
		return interpolation_lineaire(a, b, k);
	}

	static float interpolation_lineaire(float a, float b, float x)
	{
		return a * (1 - x) + b * x;
	}

	static float interpolation_cos2D(float a, float b, float c, float d, float x, float y)
	{
		float x1 = interpolation_cos(a, b, x);
		float x2 = interpolation_cos(c, d, x);
		return interpolation_cos(x1, x2, y);
	}

	
	public static void main( String arg[] )
	{
		float g[][] = new float[32][32];

		conversionCentree(g , 33 , 33 );
		
		presenter(g);
	}

	public static void normaliser(float[][][] g)
	{
		float max = -1;
		float min = Float.MAX_VALUE;
		
		for( int l = 0 ; l < g.length ; l++ )
		{
			for( int i = 0 ; i < g[0].length ; i++ )
			{
				for( int j = 0 ; j < g[0][0].length ; j++ )
				{
					if( g[l][i][j] > max )
					{
						max = g[l][i][j];
					}
					
					if( g[l][i][j] < min )
					{
						min = g[l][i][j];
					}
				}
			}
		}
		
		for( int l = 0 ; l < g.length ; l++ )
		{
			for( int i = 0 ; i < g[0].length ; i++ )
			{
				for( int j = 0 ; j < g[0][0].length ; j++ )
				{
					g[l][i][j] -= min;
					g[l][i][j] /= max-min;
				}
			}
		}
		
	}
/*
	public static float[][][] conversion(float[][][] g, int noise)
	{
		//nivellement( g );
		
		g[0] = conversion( g[0] , noise );
		
		bordure( g[0] , g[1] , false , false );
		bordure( g[0] , g[2] , false , true );
		bordure( g[0] , g[4] , true , true );
		bordure( g[0] , g[5] , true , false );
		
		
		//g[1] = conversion( g[1] , noise , true , true );
		g[2] = conversion( g[2] , noise , true , false );
		g[3] = conversion( g[3] , noise , true , false );
		g[4] = conversion( g[4] , noise , true , false );
		
		
		
		return g;
	}
*/

	static void conversion( float[][][] g, int noise )
	{
		float d[][][] = new float[g.length][g[0].length][g[0][0].length];

		int periode = 1;
		float amplitude = 1;

		ArrayList<Integer> mode = new ArrayList<Integer>();
		
		for( int b = 0 ; b < noise ; b++ )
		{
			System.out.println("	Filtre " + b + " debut");
			
			mode.add(0);
			developpementNiveau( d[0] , periode , amplitude, mode );
			
			mode.clear();
			mode.add(1);
			bordure( d[0] , d[1] , 1 );
			developpementNiveau( d[1] , periode , amplitude, mode );
			
			
			mode.clear();
			mode.add(2);
			mode.add(3);
			bordure( d[0] , d[2] , 2 );
			bordure( d[1] , d[2] , 3 );
			
			developpementNiveau( d[2] , periode , amplitude, mode );
			
			mode.clear();
			mode.add(4);
			mode.add(5);
			bordure( d[0] , d[4] , 4 );
			bordure( d[2] , d[4] , 5 );
			
			developpementNiveau( d[4] , periode , amplitude, mode );
			
			mode.clear();
			mode.add(6);
			mode.add(7);
			mode.add(5);
			bordure( d[0] , d[5] , 6 );
			bordure( d[4] , d[5] , 7 );
			bordure( d[1] , d[5] , 5 );
			
			developpementNiveau( d[5] , periode , amplitude, mode );
			
			mode.clear();
			mode.add(4);
			mode.add(10);
			mode.add(9);
			mode.add(8);
			bordure( d[1] , d[3] , 4 );
			bordure( d[2] , d[3] , 10 );
			bordure( d[4] , d[3] , 9 );
			bordure( d[5] , d[3] , 8 );
			
			developpementNiveau( d[3] , periode , amplitude, mode );
			
			//presenter(d[0]);
			
			//presenter(d[1]);
			
			for( int l = 0 ; l < 6 ; l++ )
			{
				for( int i = 0 ; i < d[0].length ; i++ )
				{
					for( int j = 0 ; j < d[0][0].length ; j++ )
					{
						g[l][i][j] += d[l][i][j];
					}
				}
			}
			
			amplitude *= 2;
			periode *= 2;
			
			System.out.println("	Filtre " + b + " fini");
		}

		//presenter( d );
	}

	private static void developpementNiveau( float d[][] , int periode , float amplitude , ArrayList<Integer> mode )
	{
		for( int i = 0 ; i < d.length ; i++ )
		{
			for( int j = 0 ; j < d[0].length ; j++ )
			{	
				if( permiSetIJBordure( i , j , mode , d.length ) )
				{
					d[i][j] = 0;
				}
			}
		}
		
		for( int i = 0 ; i < d.length ; i += periode )
		{
			for( int j = 0 ; j < d[0].length ; j += periode )
			{
				if( permiSetIJBordure( i , j , mode , d.length ) )
				{
					d[i][j] = (float) (Math.random() * amplitude);
				}
			}
		}
		//presenter( d );
		
		for( int i = 0 ; i < d.length-periode ; i += periode )
		{
			for( int j = 0 ; j < d[0].length-periode ; j += periode )
			{
				for( int k = 0 ; k < periode+1 ; k++ )
				{
					for( int l = 0 ; l < periode+1 ; l++)
					{
						float x = (float)k/(float)periode;
						float y = (float)l/(float)periode;
						
						if( permiSetIJBordure( i+k , j+l , mode , d.length ) )
						{
							d[i+k][j+l] = interpolation_cos2D( d[i][j] , d[i+periode][j] , d[i][j+periode] , d[i+periode][j+periode] , x, y);
						}
					}
				}
			}
		}
		
	}

	private static boolean permiSetIJBordure(int i, int j, ArrayList<Integer> mode , int taille)
	{
		if( mode.contains(0) )
			return true;
		
		if( mode.contains(1) && i == taille-1 )
		{
			return false;
		}
		else if( mode.contains(2) && i == taille-1 )
		{
			return false;
		}
		else if( mode.contains(3) && j == taille-1 )
		{
			return false;
		}
		else if( mode.contains(4) && i == taille-1 )
		{
			return false;
		}
		else if( mode.contains(5) && j == taille-1 )
		{
			return false;
		}
		else if( mode.contains(6) && i == taille-1 )
		{
			return false;
		}
		else if( mode.contains(7) && j == 0 )
		{
			return false;
		}
		else if( mode.contains(8) && j == 0 )
		{
			return false;
		}		
		else if( mode.contains(9) && i == 0 )
		{
			return false;
		}
		else if( mode.contains(10) && j == taille-1 )
		{
			return false;
		}
		/*
		if( sti && stj && j != 0 )
		{
			return true;
		}
		else if( sti && !stj && j != taille-1 )
		{
			return true;
		}
		else if( !sti && stj && i != 0 )
		{
			return true;
		}
		else if( !sti && !stj && i != taille-1 )
		{
			return true;
		}*/
		
		return true;
	}

	private static void bordure(float[][] ds, float[][] ds1 , int mode )
	{
		//for( int j = 0 ; j < 20 ; j++ )
		for( int i = 0 ; i < ds.length ; i++ )
		{
			// 1 - 0
			if( mode == 1 )
			{
				ds1[ds.length-1][i] = ds[ds.length-1][i];
			}
			
			// 2 - 0
			else if( mode == 2 )
			{
				ds1[ds.length-1][i] = ds[i][ds.length-1];
			}
			// 1 - 2
			else if( mode == 3 )
			{
				ds1[i][ds.length-1] = ds[i][ds.length-1];
			}
			
			// 4 - 0
			// 3 - 1
			else if( mode == 4 )
			{
				ds1[ds.length-1][i] = ds[0][i];
			}
			// 4 - 2
			// 5 - 1
			else if( mode == 5 )
			{
				ds1[i][ds.length-1] = ds[i][0];
			}
			
			// 5 - 0
			else if( mode == 6 )
			{
				ds1[ds.length-1][i] = ds[i][0];
			}
			// 5 - 4
			else if( mode == 7 )
			{
				ds1[i][0] = ds[i][0];
			}
			
			// 3 - 5
			else if( mode == 8 )
			{
				ds1[i][0] = ds[0][i];
			}
			// 3 - 4
			else if( mode == 9 )
			{
				ds1[0][i] = ds[0][i];
			}
			// 3 - 2
			else if( mode == 10 )
			{
				ds1[i][ds.length-1] = ds[0][i];
			}
			/*

			if( sti && stj )
			{
				ds1[ds.length-1-j][i] = ds[j][i];
			}
			else if( sti && !stj )
			{
				ds1[ds.length-1-j][i] = ds[i][j];
			}
			else if( !sti && stj )
			{
				ds1[ds.length-1-j][i] = ds[i][ds.length-1-j];
			}*/

		}
	}

	private static void nivellement(float[][][] g)
	{
		for( int l = 0 ; l < g.length ; l++ )
		{
			for( int i = 0 ; i < g[0].length ; i++ )
			{
				for( int j = 0 ; j < g[0][0].length ; j++ )
				{
					g[l][i][j] = (float) 0.5;
				}
			}
		}
	}
	
	public static float[][] conversionCentree(float[][] g, int it, int jt)
	{
		float d[][] = new float[g.length][g[0].length];

		int periode = 1;
		float amplitude = 1;

		for( int b = 0 ; b < 4 ; b++ )
		{
			for( int i = 0 ; i < d.length ; i++ )
			{
				for( int j = 0 ; j < d[0].length ; j++ )
				{
					d[i][j] = 0;
				}
			}
			
			float coefCentree;
			float p = 3;
			
			float mili = (float)it/2;
			float milj = (float)jt/2;
			
			for( int i = 0 ; i < d.length ; i += periode )
			{
				for( int j = 0 ; j < d[0].length ; j += periode )
				{
					
					float im = (float) (1-Math.pow( Math.abs( mili-i )/ mili , p ));
					float jm = (float) (1-Math.pow( Math.abs( milj-j )/ milj , p));
					coefCentree = im * jm;
					
					if( i > it || j > jt )
						coefCentree = 0;
					
					//System.out.println(" i " + i + " : " +  (1- Math.abs( ((float)d.length/2)-i )/ ((float)d.length/2)));

					d[i][j] = (float) (Math.random() * amplitude * coefCentree);
				}
			}
			//presenter( d );
			
			for( int i = 0 ; i < d.length-periode ; i += periode )
			{
				for( int j = 0 ; j < d[0].length-periode ; j += periode )
				{
					for( int k = 0 ; k < periode+1 ; k++ )
					{
						for( int l = 0 ; l < periode+1 ; l++)
						{
							float x = (float)k/(float)periode;
							float y = (float)l/(float)periode;
							
							
							d[i+k][j+l] = interpolation_cos2D( d[i][j] , d[i+periode][j] , d[i][j+periode] , d[i+periode][j+periode] , x, y);
						}
					}
				}
			}
			
			for( int i = 0 ; i < d.length ; i++ )
			{
				for( int j = 0 ; j < d[0].length ; j++ )
				{
					g[i][j] += d[i][j];
				}
			}
			
			amplitude *= 2;
			periode *= 2;
		}

		//presenter( d );

		return g;
	}
	
	public static float[][] normaliser(float[][] g)
	{
		float max = -1;
		float min = Float.MAX_VALUE;
		
		for( int i = 0 ; i < g.length ; i++ )
		{
			for( int j = 0 ; j < g[0].length ; j++ )
			{
				if( g[i][j] > max )
				{
					max = g[i][j];
				}
				
				if( g[i][j] < min )
				{
					min = g[i][j];
				}
			}
		}
		
		for( int i = 0 ; i < g.length ; i++ )
		{
			for( int j = 0 ; j < g[0].length ; j++ )
			{
				g[i][j] -= min;
				g[i][j] /= max-min;
			}
		}
		return g;
	}
}
